#include "SPModule.h"
#include "SPParticleSystem.h"
//----------------------------------------------------------------------------------------
// Base Class of Module
//----------------------------------------------------------------------------------------
namespace SP
{ 
	//----------------------------------------------------------------------------------------
	// SPModule
	//----------------------------------------------------------------------------------------
	SPModule::SPModule()
	{

	}
	
	SPModule::~SPModule()
	{

	}

	void SPModule::Advance( float fElapsedTime )
	{

	}
	
}

//----------------------------------------------------------------------------------------
// Gnenral Modules
//----------------------------------------------------------------------------------------
namespace SP
{
	//----------------------------------------------------------------------------------------
	// SPModuleDepthStencilState
	//----------------------------------------------------------------------------------------
	SPModuleDepthStencilState::SPModuleDepthStencilState()
	{
		m_pDepthStencilState = NULL;
	}	

	SPModuleDepthStencilState::SPModuleDepthStencilState( SPModuleDepthStencilState* archetype )
	{
		D3D11_DEPTH_STENCIL_DESC DepthStencilDesc;
		archetype->GetState()->GetDesc( &DepthStencilDesc );
		SetStateDesc( DepthStencilDesc );
	}
	
	SPModule* SPModuleDepthStencilState::SpawnInstance()
	{
		return new SPModuleDepthStencilState( this );
	}

	SPModuleDepthStencilState::~SPModuleDepthStencilState()
	{
		SAFE_RELEASE( m_pDepthStencilState );
	}

	void SPModuleDepthStencilState::SetDefaultDepthStencilState()
	{
		SAFE_RELEASE( m_pDepthStencilState );
	}

	HRESULT SPModuleDepthStencilState::SetStateDesc( const D3D11_DEPTH_STENCIL_DESC& DepthStencilDesc )
	{
		HRESULT hr = S_OK;

		SPGetD3D11DeviceContext()->OMSetDepthStencilState( NULL, 0 );
		SAFE_RELEASE( m_pDepthStencilState );

		V( SPGetD3D11Device()->CreateDepthStencilState( &DepthStencilDesc, &m_pDepthStencilState ) );
		m_bDepthEnable = DepthStencilDesc.DepthWriteMask == D3D11_DEPTH_WRITE_MASK_ALL;

		if( FAILED( hr ) )
		{	
			SAFE_RELEASE( m_pDepthStencilState );
			m_bDepthEnable = true;
		}
		return hr;
	}


	//----------------------------------------------------------------------------------------
	// SPModuleBlendState
	//----------------------------------------------------------------------------------------
	SPModuleBlendState::SPModuleBlendState()
	{
		m_pBlendState = NULL;
	}

	SPModuleBlendState::SPModuleBlendState( SPModuleBlendState* archetype )
	{
		D3D11_BLEND_DESC BlendStateDesc;
		archetype->GetState()->GetDesc( &BlendStateDesc );
		SetStateDesc( BlendStateDesc );
	}

	SPModule* SPModuleBlendState::SpawnInstance()
	{
		return new SPModuleBlendState( this );
	}

	SPModuleBlendState::~SPModuleBlendState()
	{
		SAFE_RELEASE( m_pBlendState );
	}

	void SPModuleBlendState::SetDefaultBlendState()
	{
		SAFE_RELEASE( m_pBlendState );
	}

	HRESULT SPModuleBlendState::SetStateDesc( const D3D11_BLEND_DESC& BlendStateDesc )
	{
		HRESULT hr = S_OK;	

		float vBlendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
		SPGetD3D11DeviceContext()->OMSetBlendState( NULL, vBlendFactor, 0xFFFFFFFF  );
		SAFE_RELEASE( m_pBlendState );

		V( SPGetD3D11Device()->CreateBlendState( &BlendStateDesc, &m_pBlendState ) );
		if ( FAILED( hr ) )
			SAFE_RELEASE( m_pBlendState );

		return hr; 
	}

	//----------------------------------------------------------------------------------------
	// SPModuleRasterizerState
	//----------------------------------------------------------------------------------------
	SPModuleRasterizerState::SPModuleRasterizerState()
	{
		m_pRasterizerState = NULL;
	}

	SPModuleRasterizerState::SPModuleRasterizerState( SPModuleRasterizerState* archetype )
	{
		D3D11_RASTERIZER_DESC RasterizerDesc;
		archetype->GetState()->GetDesc( &RasterizerDesc );
		SetStateDesc( RasterizerDesc );
	}

	SPModule* SPModuleRasterizerState::SpawnInstance()
	{
		return new SPModuleRasterizerState( this );
	}

	SPModuleRasterizerState::~SPModuleRasterizerState()
	{
		SAFE_RELEASE( m_pRasterizerState );
	}

	void SPModuleRasterizerState::SetDefaultRasterizerState()
	{
		SAFE_RELEASE( m_pRasterizerState );
	}

	HRESULT SPModuleRasterizerState::SetStateDesc( const D3D11_RASTERIZER_DESC & RasterizerDesc )
	{
		HRESULT hr = S_OK;

		SPGetD3D11DeviceContext()->RSSetState( NULL );
		SAFE_RELEASE( m_pRasterizerState );

		V( SPGetD3D11Device()->CreateRasterizerState( &RasterizerDesc, &m_pRasterizerState ) );
		if( FAILED( hr ) )
			SAFE_RELEASE( m_pRasterizerState );

		return hr;
	}


	//----------------------------------------------------------------------------------------
	// SPModuleEmitterTransform
	//----------------------------------------------------------------------------------------
	SPModuleEmitterTransform::SPModuleEmitterTransform()
	{
		m_vStart = XMFLOAT3( 0.0f, 0.0f ,0.0f );
		m_vEnd = XMFLOAT3( 0.0f, 0.0f, 0.0f );
	}

	SPModuleEmitterTransform::SPModuleEmitterTransform( SPModuleEmitterTransform* archetype )
	{
		m_vEnd = archetype->m_vEnd;
		m_vStart = archetype->m_vStart;
	}

	void SPModuleEmitterTransform::SetParm( const XMFLOAT3& vStart, const XMFLOAT3& vEnd )
	{
		m_vStart = vStart;
		m_vEnd = vEnd;
	}

	void SPModuleEmitterTransform::GetParm( XMFLOAT3& vStart, XMFLOAT3& vEnd )
	{
		vStart = m_vStart;
		vEnd = m_vEnd;
	}

	//----------------------------------------------------------------------------------------
	// SPModuleEmitterRotation
	//----------------------------------------------------------------------------------------
	SPModuleEmitterRotation::SPModuleEmitterRotation()
	{

	}

	SPModuleEmitterRotation::SPModuleEmitterRotation(  SPModuleEmitterRotation* archetype )
		: SPModuleEmitterTransform( archetype )
	{

	}

	SPModule* SPModuleEmitterRotation::SpawnInstance()
	{
		return new SPModuleEmitterRotation( this );
	}

	XMMATRIX SPModuleEmitterRotation::GetTransformMatrix( float fLife )
	{
		XMVECTOR start = XMLoadFloat3( &m_vStart );
		XMVECTOR end = XMLoadFloat3( &m_vEnd );

		XMVECTOR lerp = XMVectorLerp( start , end, fLife );

		return XMMatrixRotationRollPitchYawFromVector( lerp );
	}

	//----------------------------------------------------------------------------------------
	// SPModuleEmitterScale
	//----------------------------------------------------------------------------------------
	SPModuleEmitterScale::SPModuleEmitterScale()
	{

	}

	SPModuleEmitterScale::SPModuleEmitterScale(  SPModuleEmitterScale* archetype )
		: SPModuleEmitterTransform( archetype )
	{

	}

	SPModule* SPModuleEmitterScale::SpawnInstance()
	{
		return new SPModuleEmitterScale( this );
	}

	XMMATRIX SPModuleEmitterScale::GetTransformMatrix( float fLife )
	{
		XMVECTOR start = XMLoadFloat3( &m_vStart );
		XMVECTOR end = XMLoadFloat3( &m_vEnd );

		XMVECTOR lerp = XMVectorLerp( start , end, fLife );

		return XMMatrixScalingFromVector( lerp );
	}


	//----------------------------------------------------------------------------------------
	// SPModuleEmitterTranslation
	//----------------------------------------------------------------------------------------
	SPModuleEmitterTranslation::SPModuleEmitterTranslation()
	{

	}

	SPModuleEmitterTranslation::SPModuleEmitterTranslation(  SPModuleEmitterTranslation* archetype )
		: SPModuleEmitterTransform( archetype )
	{

	}

	SPModule* SPModuleEmitterTranslation::SpawnInstance()
	{
		return new SPModuleEmitterTranslation( this );
	}

	XMMATRIX SPModuleEmitterTranslation::GetTransformMatrix( float fLife )
	{
		XMVECTOR start = XMLoadFloat3( &m_vStart );
		XMVECTOR end = XMLoadFloat3( &m_vEnd );

		XMVECTOR lerp = XMVectorLerp( start , end, fLife );

		return XMMatrixTranslationFromVector( lerp );
	}

	//----------------------------------------------------------------------------------------
	// SPModuleEmitterColour
	//----------------------------------------------------------------------------------------
	SPModuleEmitterColour::SPModuleEmitterColour()
	{
		m_vColourStart = XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f );
		m_vColourEnd = XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f );
	}

	SPModuleEmitterColour::SPModuleEmitterColour( SPModuleEmitterColour* archetpye )
	{
		m_vColourStart = archetpye->m_vColourStart;
		m_vColourEnd = archetpye->m_vColourEnd;	
	}

	SPModule* SPModuleEmitterColour::SpawnInstance()
	{
		return new SPModuleEmitterColour( this );
	}

	XMVECTOR SPModuleEmitterColour::GetColour( float fLife )
	{
		XMVECTOR start = XMLoadFloat4( &m_vColourStart );
		XMVECTOR end = XMLoadFloat4( &m_vColourEnd );
		return XMVectorLerp( start, end, fLife );
	}

	//----------------------------------------------------------------------------------------
	// SPModuleEmitterCollision
	//----------------------------------------------------------------------------------------

}

//----------------------------------------------------------------------------------------
// particle Emitter Modules
//----------------------------------------------------------------------------------------
namespace SP
{
	//----------------------------------------------------------------------------------------
	// SPModuleParticleVector
	//----------------------------------------------------------------------------------------


	//----------------------------------------------------------------------------------------
	// SPModuleInitVector
	//----------------------------------------------------------------------------------------
	SPModuleInitVector::SPModuleInitVector()
	{
		m_pVectors = NULL;
		m_nParticleCount = 0;
	}

	SPModuleInitVector::SPModuleInitVector( SPModuleInitVector* archetype )
		: m_vConstant( &archetype->m_vConstant )
	{
		m_pVectors = NULL;
		m_nParticleCount = 0;
	}

	SPModule* SPModuleInitVector::SpawnInstance()
	{
		return new SPModuleInitVector( this );
	}

	SPModuleInitVector::~SPModuleInitVector()
	{
		SAFE_DELETE( m_pVectors );
	}

	void SPModuleInitVector::Emit( UINT idx )
	{
		XMStoreFloat3( m_pVectors+idx, m_vConstant.CalcValue() );
	}

	void SPModuleInitVector::Emit( UINT idx, XMVECTOR vOrigin )
	{
		XMStoreFloat3( m_pVectors+idx, m_vConstant.CalcValue() + vOrigin );
	}

	XMVECTOR SPModuleInitVector::GetVector( UINT idx, float fLife )
	{
		return XMLoadFloat3( m_pVectors + idx );
	}

	void SPModuleInitVector::AdvanceVector( UINT idx, XMVECTOR delta )
	{
		XMVECTOR v = XMLoadFloat3( m_pVectors + idx );
		v += delta;
		XMStoreFloat3( m_pVectors +idx, v );
	}

	void SPModuleInitVector::Advance( float fElapsedTime )
	{
		SPEmitterParticle* pEP = static_cast<SPEmitterParticle*>( m_pEmitter );
		if ( pEP->GetInitialAllocationCount() != m_nParticleCount )
		{
			m_nParticleCount = pEP->GetInitialAllocationCount();
			SAFE_DELETE( m_pVectors );
			m_pVectors = new XMFLOAT3[m_nParticleCount];

			Init();
		}
	}

	void SPModuleInitVector::Init()
	{
		for ( UINT i = 0; i < m_nParticleCount; i++ )
		{
			Emit( i );
		}
	}

	//----------------------------------------------------------------------------------------
	//  SPModuleVectorOverLife
	//----------------------------------------------------------------------------------------
	SPModuleVectorOverLife::SPModuleVectorOverLife()
	{	
		m_pStartVectors= NULL;
		m_pEndVectors = NULL;
		m_nParticleCount = 0;
	}

	SPModuleVectorOverLife::SPModuleVectorOverLife( SPModuleVectorOverLife* archetype )
		: m_vEnd( &archetype->m_vEnd ),
		m_vStart( &archetype->m_vStart )
	{
		m_pStartVectors= NULL;
		m_pEndVectors = NULL;
		m_nParticleCount = 0;
	}

	SPModule* SPModuleVectorOverLife::SpawnInstance()
	{
		return new SPModuleVectorOverLife( this );
	}

	SPModuleVectorOverLife::~SPModuleVectorOverLife()
	{
		SAFE_DELETE( m_pStartVectors );
		SAFE_DELETE( m_pEndVectors );
	}

	void SPModuleVectorOverLife::Emit( UINT idx )
	{
		XMStoreFloat3( m_pStartVectors+idx, m_vStart.CalcValue() );
		XMStoreFloat3( m_pEndVectors+idx, m_vEnd.CalcValue() );
	}

	void SPModuleVectorOverLife::Emit( UINT idx, XMVECTOR vOrigin )
	{
		
		XMStoreFloat3( m_pStartVectors+idx, m_vStart.CalcValue() + vOrigin );
		XMStoreFloat3( m_pEndVectors+idx, m_vEnd.CalcValue() + vOrigin );
	}

	XMVECTOR SPModuleVectorOverLife::GetVector( UINT idx, float fLife )
	{
		XMVECTOR start = XMLoadFloat3( m_pStartVectors+idx );
		XMVECTOR end = XMLoadFloat3( m_pEndVectors+idx );
		return XMVectorLerp( start, end, fLife );
	}

	void SPModuleVectorOverLife::Advance( float fElapsedTime )
	{
		SPEmitterParticle* pEP = static_cast<SPEmitterParticle*>( m_pEmitter );
		if ( pEP->GetInitialAllocationCount() != m_nParticleCount )
		{
			m_nParticleCount = pEP->GetInitialAllocationCount();
			SAFE_DELETE( m_pEndVectors );
			SAFE_DELETE( m_pStartVectors );
			m_pEndVectors = new XMFLOAT3[m_nParticleCount];
			m_pStartVectors = new XMFLOAT3[m_nParticleCount];

			Init();
		}
	}

	void SPModuleVectorOverLife::Init()
	{
		for ( UINT i = 0; i < m_nParticleCount; i++ )
		{
			Emit( i );
		}
	}

	//----------------------------------------------------------------------------------------
	//  SPModuleParticleFloat
	//----------------------------------------------------------------------------------------

	//----------------------------------------------------------------------------------------
	//  SPModuleInitFloat
	//----------------------------------------------------------------------------------------
	SPModuleInitFloat::SPModuleInitFloat()
	{
		m_pFloats = NULL; 
	}

	SPModuleInitFloat::SPModuleInitFloat( SPModuleInitFloat* archetype )
		: m_fConstant( &archetype->m_fConstant )
	{
		m_pFloats = NULL; 
	}

	SPModule* SPModuleInitFloat::SpawnInstance()
	{
		return new SPModuleInitFloat( this );
	}

	SPModuleInitFloat::~SPModuleInitFloat()
	{
		SAFE_DELETE( m_pFloats );
	}

	void SPModuleInitFloat::Emit( UINT idx )
	{
		m_pFloats[idx] = m_fConstant.CalcValue();
	}

	FLOAT SPModuleInitFloat::GetFloat( UINT idx, float fLife )
	{
		return m_pFloats[idx];
	}

	void SPModuleInitFloat::Advance( float fElapsedTime )
	{
		SPEmitterParticle* pEP = static_cast<SPEmitterParticle*>( m_pEmitter );
		if ( pEP->GetInitialAllocationCount() != m_nParticleCount )
		{
			m_nParticleCount = pEP->GetInitialAllocationCount();
			SAFE_DELETE( m_pFloats );
			m_pFloats = new FLOAT[m_nParticleCount];

			Init();
		}
	}

	void SPModuleInitFloat::Init()
	{			
		for ( UINT i = 0; i < m_nParticleCount; i++ )
		{
			Emit( i );
		}
	}


	//----------------------------------------------------------------------------------------
	//  SPModuleFloatOverLife
	//----------------------------------------------------------------------------------------
	SPModuleFloatOverLife::SPModuleFloatOverLife()
	{
		m_pStartFloats = NULL; 
		m_pEndFloats = NULL; 
	}

	SPModuleFloatOverLife::SPModuleFloatOverLife( SPModuleFloatOverLife* archetype )
		: m_fStart( archetype->m_fStart ),
		m_fEnd( archetype->m_fEnd )
	{
		m_pStartFloats = NULL; 
		m_pEndFloats = NULL; 
	}

	SPModule* SPModuleFloatOverLife::SpawnInstance()
	{
		return new SPModuleFloatOverLife( this );
	}

	SPModuleFloatOverLife::~SPModuleFloatOverLife()
	{
		SAFE_DELETE( m_pStartFloats );
		SAFE_DELETE( m_pEndFloats );
	}

	void SPModuleFloatOverLife::Emit( UINT idx )
	{
		m_pStartFloats[idx] = m_fStart.CalcValue();
		m_pEndFloats[idx] = m_fEnd.CalcValue();
	}

	FLOAT SPModuleFloatOverLife::GetFloat( UINT idx, float fLife )
	{
		return m_pStartFloats[idx] * ( 1 - fLife ) + m_pEndFloats[idx] * fLife;
	}

	void SPModuleFloatOverLife::Advance( float fElapsedTime )
	{
		SPEmitterParticle* pEP = static_cast<SPEmitterParticle*>( m_pEmitter );
		if ( pEP->GetInitialAllocationCount() != m_nParticleCount )
		{
			m_nParticleCount = pEP->GetInitialAllocationCount();
			SAFE_DELETE( m_pStartFloats );
			SAFE_DELETE( m_pEndFloats );
			m_pStartFloats = new FLOAT[m_nParticleCount];
			m_pEndFloats = new FLOAT[m_nParticleCount];

			Init();
		}
	}

	void SPModuleFloatOverLife::Init()
	{
		for ( UINT i = 0; i < m_nParticleCount; i++ )
		{
			Emit( i );
		}
	}

}

//----------------------------------------------------------------------------------------
// Beam Emitter Modules
//----------------------------------------------------------------------------------------
namespace SP
{
	//----------------------------------------------------------------------------------------
	// SPModuleBeamShape
	//----------------------------------------------------------------------------------------
	SPModuleBeamShape::SPModuleBeamShape()
	{
		m_nShapeType = 0;
	}

	SPModuleBeamShape::SPModuleBeamShape( SPModuleBeamShape* archetype )
	{
		m_nShapeType = archetype->m_nShapeType;
		m_bOverLife = archetype->m_bOverLife;
		m_vEndCenterRadius = archetype->m_vEndCenterRadius;
		m_vStartCenterRadius = archetype->m_vStartCenterRadius;
	}

	SPModule* SPModuleBeamShape::SpawnInstance()
	{
		return new SPModuleBeamShape( this );
	}

	void SPModuleBeamShape::GetCircle( XMFLOAT3& center, FLOAT& radius, FLOAT life )
	{
		if ( m_bOverLife )
		{
			XMVECTOR vStart = XMLoadFloat4( &m_vStartCenterRadius );
			XMVECTOR vEnd = XMLoadFloat4( &m_vEndCenterRadius );

			XMVECTOR vResult = XMVectorLerp( vStart, vEnd, life );
			XMStoreFloat3( &center, vResult );
			radius = XMVectorGetW( vResult );
		}
		else
		{
			center.x = m_vStartCenterRadius.x;
			center.y = m_vStartCenterRadius.y;
			center.z = m_vStartCenterRadius.z;
			radius = m_vStartCenterRadius.w;
		}
	}

	//----------------------------------------------------------------------------------------
	// SPModuleBeamTerminal
	//----------------------------------------------------------------------------------------
	SPModuleBeamTerminal::SPModuleBeamTerminal()
	{
		m_bCPOverLife = FALSE;
		m_bSPOverLife = FALSE;
		m_vCPStart = XMFLOAT3( 0.0f, 0.0f, 0.0f );
		m_vSPStart = XMFLOAT3( 0.0f, 0.0f, 0.0f );
	}

	SPModuleBeamTerminal::SPModuleBeamTerminal(  SPModuleBeamTerminal* archetype )
	{
		m_bCPOverLife = archetype->m_bCPOverLife;
		m_bSPOverLife = archetype->m_bSPOverLife;
		m_vCPEnd = archetype->m_vCPEnd;
		m_vCPStart = archetype->m_vCPStart;
		m_vSPEnd = archetype->m_vSPEnd;
		m_vSPStart = archetype->m_vSPStart;
	}

	SPModule* SPModuleBeamTerminal::SpawnInstance()
	{
		return new SPModuleBeamTerminal( this );
	}

	void SPModuleBeamTerminal::GetCP( XMFLOAT3& cp, FLOAT life )
	{
		if ( m_bCPOverLife )
		{
			XMVECTOR vStart = XMLoadFloat3( &m_vCPStart );
			XMVECTOR vEnd = XMLoadFloat3( &m_vCPEnd );

			XMVECTOR vResult = XMVectorLerp( vStart, vEnd, life );
			XMStoreFloat3( &cp, vResult );
		}
		else
		{
			cp = m_vCPStart;
		}		
	}

	void SPModuleBeamTerminal::GetSP( XMFLOAT3& sp, FLOAT life )
	{
		if ( m_bSPOverLife )
		{
			XMVECTOR vStart = XMLoadFloat3( &m_vSPStart );
			XMVECTOR vEnd = XMLoadFloat3( &m_vSPEnd );

			XMVECTOR vResult = XMVectorLerp( vStart, vEnd, life );
			XMStoreFloat3( &sp, vResult );
		}
		else
		{
			sp = m_vSPStart;
		}		
	}
}

//----------------------------------------------------------------------------------------
// AnimTrail Emitter Modules
//----------------------------------------------------------------------------------------
namespace SP
{

	//----------------------------------------------------------------------------------------
	//
	//----------------------------------------------------------------------------------------
}

//----------------------------------------------------------------------------------------
// Mesh Emitter Modules
//----------------------------------------------------------------------------------------
namespace SP
{

}